#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "../Common/Log.hpp"
#include "../Common/Util.hpp"
namespace ns_runner
{
    using namespace ns_log;
    class Run
    {
    public:
        Run() {}
        ~Run() {}
        // 资源限制
        static void LimitResource(int cpu, int mem)
        {
            // 设置运行时间限制
            struct rlimit cpu_time;
            cpu_time.rlim_max = RLIM_INFINITY;
            cpu_time.rlim_cur = cpu;
            setrlimit(RLIMIT_CPU, &cpu_time);

            // 限制内存
            struct rlimit mem_limit;
            mem_limit.rlim_max = RLIM_INFINITY;
            mem_limit.rlim_cur = mem * 1024; // kb为单位
            setrlimit(RLIMIT_AS, &mem_limit);
        }
        static int Running(const std::string &filename, int cpu_time, int mem)
        {
            umask(0);
            // 先打开对应三个文件
            std::string execute = FileTool::FileSplice::SpliceExePathName(filename);
            std::string stdinlogfile = FileTool::FileSplice::SpliceRunStdin(filename);
            std::string stdoutlogfile = FileTool::FileSplice::SpliceRunStdout(filename);
            std::string stderrlogfile = FileTool::FileSplice::SpliceRunStderr(filename);
            int stdin_log_fd = open(stdinlogfile.c_str(), O_CREAT | O_RDONLY, 0644);
            int stdout_log_fd = open(stdoutlogfile.c_str(), O_CREAT | O_WRONLY, 0644);
            int stderr_log_fd = open(stderrlogfile.c_str(), O_CREAT | O_WRONLY, 0644);

            if (stdin_log_fd < 0 || stdout_log_fd < 0 || stderr_log_fd < 0)
            {
                LOG(FATAL, "run文件打开失败!\n");
                return -1;//走到这里代表内部错误，返回给上层判断即可
            }
            pid_t pid = fork();
            if (pid < 0)
            {
                LOG(FATAL, "fork error!\n");
                close(stdin_log_fd);
                close(stdout_log_fd);
                close(stderr_log_fd);
                return -2;
            }
            else if (pid == 0)
            {
                //先重定向---后程序替换
                dup2(stdin_log_fd, 0);
                dup2(stdout_log_fd, 1);
                dup2(stderr_log_fd, 2);

                LimitResource(cpu_time, mem); // 资源限制

                execl(execute.c_str(), execute.c_str(), nullptr);
                LOG(FATAL, "程序替换错误!\n");
                exit(1);
            }
            else
            {
                close(stdin_log_fd);
                close(stdout_log_fd);
                close(stderr_log_fd);
                int res = 0;
                waitpid(pid, &res, 0);
                LOG(INFO,"运行结束,info: %d ,运行的程序名：%s\n", res & 0x7F,execute.c_str());
                return res & 0x7F; // 取出信号返回给上层
            }
        }
    };
}
